﻿using System;

using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls.Classes;
using System.Drawing;
using System.Reflection;
using Silvermoon.Shapes;
using System.IO;
using Silvermoon.Animations;
using Silvermoon.Core;
using Silvermoon.Controls.Interfaces;
using Silvermoon.Controls.Base;
using Silvermoon.Interfaces;
using Silvermoon.Windows;
using System.Diagnostics;
using Silvermoon.UI;
using Silvermoon.OpenGL;
using Silvermoon.Controls.Sys;
using Silvermoon.Hardware;
using Silvermoon.Utils;
using Silvermoon.Classes;
using System.Threading;


namespace Silvermoon.Controls
{
    /// <summary>
    /// Control that hosts controls having a toolbar and a keyboard panel to access.
    /// </summary>
    public class Window : FormBase, ICompositeControl, IColor
    {
        #region classes


        private class ToolbarContainer : Decorator
        {
            public override bool CanFocus { get { return false; } }

        }

        protected class InternalKeyboardContainer : Control
        {
            public Keyboard Keyboard { get; set; }

            protected override void OnLayout()
            {
                if (this.Keyboard != null) Keyboard.Size = Size;
            }

            protected internal override void OnRender(Renderer renderer)
            {
                if (Keyboard != null) renderer.RenderControl(Keyboard);
            }

            protected internal override void OnTouchDown(TouchEventArgs e)
            {
                Keyboard.Parent = this;
                e.FocusSet = true;
                base.OnTouchDown(e);
            }

            protected internal override IEnumerable<Control> GetAttachedChildren()
            {
                Keyboard.Parent = this;
                yield return Keyboard;
            }

        }

        private class ControlsPanel : Panel
        {
            protected override Shape CreateDefaultBackground() { return null; }

            public override bool CanFocus { get { return false; } }
        }

        #endregion
        #region accessors

        public static PropertyAccessor<Window, Color> ToolbarColorProperty = PropertyAccessor.Register<Window, Color>("",
            e => e.ToolbarColor,
            (e, v) => e.ToolbarColor = v);


        private static PropertyAccessor<Window, float> KeyboardVisibilityProperty = PropertyAccessor.Register<Window, float>("",
            e => e.KeyboardVisibility,
            (e, v) => e.KeyboardVisibility = v);

        private static PropertyAccessor<Window, float> ToolbarTransitionProperty = PropertyAccessor.Register<Window, float>("",
            c => c.ToolbarTransition,
            (c, v) => c.ToolbarTransition = v);

        #endregion
        #region fields

        private bool showSymbols = false;
        private Margin titleMargin = new Margin(8, 4, 8, 8);
        private StringShape titleShape;
        private Decorator toolbarContainer;
        private Shape toolbarBackground;
        private int toolbarOpacity = 255;
        private float toolbarTransition = 0f;
        private float keyboardVisibility = 0f;
        private static Keyboard keyboard;
        private bool isKeyboardVisible;
        private bool isKeyboardAlwaysVisible;
        private ToolbarBase visibleToolbar;
        private ToolbarBase toolbar;
        private InternalKeyboardContainer keyboardContainer;

        private ControlsPanel controlsPanel;
        #endregion
        #region ctor

        public static readonly VisualStateGroup KeyboardGroup = new VisualStateGroup(
                    new VisualState("KeyboardHidden", 350),
                    new VisualState("KeyboardShown",
                        new FloatTransition
                        {
                            Duration = 350,
                            EasingFunction = PowerEase.Out, // SineEase.Instance.
                            Property = KeyboardVisibilityProperty,
                            To = 1f
                        }
                    )
                );

        static Window()
        {
            VisualStateManager manager = new VisualStateManager(KeyboardGroup);
            VisualStateManager.RegisterClassManager(typeof(Window), manager);
        }

        public Window()
            : base()
        {
            Margin = Margin.Zero;
            controlsPanel = new ControlsPanel();
            Height = Keyboard.KeyboardHeight;
            toolbarContainer = new ToolbarContainer();
            VisibleControls.Add(controlsPanel, toolbarContainer);
        }


        public ControlCollection Controls { get { return controlsPanel.Controls; } }


        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool dispose)
        {
            if (threads != null) threads.Dispose();
            threads = null;

            if (toolbarContainer != null)
            {
                toolbarContainer.Control = null;
                toolbarContainer = null;
            }
            DisposeObject(visibleToolbar);
            DisposeObject(toolbar);
            isKeyboardVisible = false;
            if (keyboard != null)
            {
                VisibleControls.Remove(keyboard);
            }
            base.Dispose(dispose);
            controlsPanel = null;
        }

        #endregion
        #region Props

        protected InternalKeyboardContainer KeyboardContainer
        {
            get
            {
                if (keyboardContainer == null)
                {
                    keyboardContainer = new InternalKeyboardContainer();
                    keyboardContainer.Keyboard = Keyboard;
                    VisibleControls.Append(controlsPanel, keyboardContainer);
                }
                return keyboardContainer;
            }
        }

        protected override bool IsWindow
        {
            get { return true; }
        }

        protected StringShape TitleShape
        {
            get { return titleShape; }
            set
            {
                if (titleShape != value)
                {
                    StringShape oldValue = titleShape;
                    titleShape = value;
                    OnTitleShapeChanged(oldValue);
                }
            }
        }

        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        public string Title
        {
            get { return titleShape != null ? titleShape.Text : string.Empty; }
            set
            {
                if (Title != value)
                {
                    if (string.IsNullOrEmpty(value))
                    {
                        TitleShape = null;
                    }
                    else
                    {
                        if (titleShape == null)
                        {
                            TitleShape = new StringShape
                            {
                                Size = new Size(0, 32),
                                LineAlignment = Alignment.Center,
                                Alignment = Alignment.Near,
                                LineMode = LineMode.EndEllipsis,
                                FontScale = 0.75f
                            };
                        }
                        titleShape.Text = value;
                        OnTitleChanged();
                    }
                }
            }
        }
        public Orientation ToolbarOrientation
        {
            get
            {
                Orientation result = Orientation;
                if (result != Orientation.Portrait)
                {
                    if (visibleToolbar != null && !visibleToolbar.EnableLandscape) return Orientation.Portrait;
                }
                return result;
            }
        }


        /// <summary>
        /// Gets the rectangle that represents the client area of the control.
        /// This area can be partially overlapped by an expanded toolbar or keyboard.
        /// To get the bounds which are not overlapped see <see cref="P:VisibleBounds"/> property.
        /// </summary>
        public override Rectangle ClientBounds
        {
            get
            {
                Rectangle bounds = base.ClientBounds;
                ToolbarBase toolbar = visibleToolbar;
                if (!((toolbar == null) || toolbarOpacity != Control.Opaque))
                {

                    int wh = toolbar != null ? toolbar.CollapsedSize : 0;
                    if (ToolbarOrientation == Orientation.Portrait)
                    {
                        bounds.Height -= wh;
                    }
                    else
                    {
                        bounds.Width -= wh;
                    }
                }
                if (isKeyboardVisible && keyboardVisibility == 1f) bounds.Height -= KeyboardRect.Height;
                Rectangle r = GetTitleRect();
                if (r.Height > 0)
                {
                    bounds.Height -= r.Height;
                    bounds.Y += r.Height;
                }
                return bounds;
            }
        }

        /// <summary>
        ///  Gets the bounds of the client area which is not overlapped by expanded toolbar or keyboard.
        ///  See also <seealso cref="P:ClientBounds"/> property.
        /// </summary>
        public Rectangle VisibleRect
        {
            get
            {
                Rectangle bounds = base.ClientBounds;
                ToolbarBase toolbar = Toolbar;
                Orientation orientation = ToolbarOrientation;

                int b = bounds.Bottom;
                int toolbarSize = toolbar != null ? toolbar.DesiredSize : 0;
                if (orientation == Orientation.Portrait)
                {
                    bounds.Height -= toolbarSize;
                }
                else
                {
                    bounds.Width -= toolbarSize;
                }
                if (isKeyboardVisible)
                {
                    int bottom = b - ((toolbar != null && orientation == Orientation.Portrait ? toolbar.CollapsedSize : 0) + KeyboardRect.Height);
                    int h2 = bottom - bounds.Top;
                    if (bounds.Height > h2) bounds.Height = h2;
                }
                return bounds;
            }
        }

        /// <summary>
        /// Gets or sets the background for the toolbar if available.
        /// </summary>
        public Shape ToolbarBackground
        {
            get { return toolbarBackground; }
            set
            {
                if (toolbarBackground != value)
                {
                    toolbarBackground = value;
                    toolbarContainer.Background = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the color of the toolbar.
        /// </summary>
        public Color ToolbarColor
        {
            get
            {
                ColorShape shape = ToolbarBackground as ColorShape;
                return shape != null ? shape.Color : Color.Empty;
            }
            set
            {
                ColorShape shape = ToolbarBackground as ColorShape;
                if (shape != null)
                {
                    if (shape.Color != value)
                    {
                        shape.Color = value;
                        Invalidate(InvalidationFlag.Color);
                    }
                }
            }
        }

        public Color ToolbarTextColor
        {
            get { return toolbarContainer.TextColor; }
            set
            {
                toolbarContainer.TextColor = value;
            }
        }


        protected static Keyboard GetKeyboard()
        {
            if (keyboard == null) keyboard = new Keyboard();
            return keyboard;
        }

        /// <summary>
        /// Gets the KeyboardPanel.
        /// </summary>
        public Keyboard Keyboard
        {
            get
            {
                if (keyboard == null)
                {
                    keyboard = GetKeyboard();
                }
                KeyboardContainer.Keyboard = keyboard;

                return keyboard;
            }
            protected set { keyboard = value; }
        }

        /// <summary>
        /// Gets or sets the visibility of the keyboard between 0 and 1 where 0 is completely hidden and 1 is completely visible.
        /// </summary>
        public float KeyboardVisibility
        {
            get { return keyboardVisibility; }
            protected set
            {
                value = ValidateKeyboardVisibility(value);
                if (keyboardVisibility != value)
                {
                    keyboardVisibility = value;
                    OnKeyboardVisibilityChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the transition factor of the toolbar between 0 and 1 where 0 is completely hidden and 1 is completely visible.
        /// </summary>
        protected float ToolbarTransition
        {
            get { return toolbarTransition; }
            set
            {
                value = ValidateToolbarVisibility(value);
                if (value != toolbarTransition)
                {
                    toolbarTransition = value;
                    OnToolbarVisibilityChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets whether to show the toolbar.
        /// </summary>
        public bool IsToolbarVisible
        {
            get { return visibleToolbar != null ? visibleToolbar.Visible : false; }
            set
            {
                if (visibleToolbar == null) value = false;
                if (IsToolbarVisible != value)
                {
                    visibleToolbar.Visible = value;
                    OnShowToolbarChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the toolbar.
        /// Note that a previous toolbar is NOT automatically being disposed!
        /// </summary>
        public ToolbarBase Toolbar
        {
            get { return visibleToolbar; }
            set
            {
                if (toolbar != value)
                {
                    ToolbarBase oldValue = toolbar;
                    toolbar = value;
                    OnToolbarChanged(oldValue);
                }
            }
        }

        /// <summary>
        /// Gets or sets whether the keyboard is visible:
        /// </summary>
        public bool IsKeyboardVisible
        {
            get { return isKeyboardVisible; }
            set
            {
                if (isKeyboardAlwaysVisible) value = true;
                if (!showSymbols && (Orientation == Orientation.Landscape && PhoneInfo.HasLandscapeKeyboard)) value = false;
                if (!value) showSymbols = false;
                if (isKeyboardVisible != value)
                {
                    isKeyboardVisible = value;
                    OnKeyboardVisibleChanged(value);
                }
            }
        }


        /// <summary>
        /// Gets or sets whether the keyboard is always visible.
        /// </summary>
        public bool IsKeyboardAlwaysVisible
        {
            get { return isKeyboardAlwaysVisible; }
            set
            {
                if (isKeyboardAlwaysVisible != value)
                {
                    isKeyboardAlwaysVisible = value;
                    OnKeyboardAlwaysVisibleChanged();
                }
            }
        }

        /// <summary>
        /// Gets the bounds of the toolbar.
        /// </summary>
        protected Rectangle ToolbarRect
        {
            get
            {
                if (visibleToolbar == null) return Rectangle.Empty;
                if (ToolbarOrientation == Orientation.Portrait)
                {
                    return GetToolbarPortraitRect();
                }
                else
                {
                    return GetToolbarLandscapeRect();
                }
            }
        }

        private Rectangle GetToolbarPortraitRect()
        {
            ToolbarBase toolbar = visibleToolbar;
            int h = toolbar != null ? toolbar.CurrentSize : 0;
            if (toolbarTransition != 1f)
            {
                h = (int)((toolbarTransition) * (h - 0)) + 0;
            }

            return new Rectangle(0, Height - h, Width, h);
        }

        private Rectangle GetToolbarLandscapeRect()
        {
            ToolbarBase toolbar = visibleToolbar;
            int w = toolbar != null ? toolbar.CurrentSize : 0;
            if (toolbarTransition != 1f)
            {
                int w1 = 0;
                w = (int)((toolbarTransition) * (w - w1)) + w1;
            }
            return new Rectangle(Width - w, 0, w, Height);
        }

        /// <summary>
        /// Gets the bounds of the keyboard.
        /// </summary>
        public Rectangle KeyboardRect
        {
            get
            {
                if (keyboard == null) return Rectangle.Empty;

                if (ToolbarOrientation == Orientation.Portrait)
                {
                    int h0 = ToolbarRect.Height;
                    if (visibleToolbar != null && h0 > visibleToolbar.CollapsedSize) h0 = visibleToolbar.CollapsedSize;
                    int h = (int)(keyboardVisibility * (keyboard.Height + h0));
                    return new Rectangle(0, Height - h, Width, keyboard.Height);
                }
                else
                {
                    int w0 = ToolbarRect.Width;
                    if (visibleToolbar != null && w0 > visibleToolbar.CollapsedSize) w0 = visibleToolbar.CollapsedSize;
                    int h = (int)(keyboardVisibility * keyboard.Height);
                    return new Rectangle(0, Height - h, Width - w0, keyboard.Height);
                }
            }
        }

        /// <summary>
        /// Gets or sets the opacity for the toolbar between 0 and 255.
        /// </summary>
        public int ToolbarOpacity
        {
            get { return toolbarOpacity; }
            set
            {
                if (value < 0) value = 0;
                else if (value > Control.Opaque) value = Control.Opaque;
                if (toolbarOpacity != value)
                {
                    toolbarOpacity = value;
                    OnToolbarOpacityChanged();
                }
            }
        }

        #endregion
        #region methods

        protected virtual Rectangle GetTitleRect()
        {
            if (titleShape == null) return Rectangle.Empty;
            return new Rectangle(0, 0, Width, titleShape.Height + titleMargin.Height);
            //            return titleMargin.LayoutChild(new Rectangle(0, 0, Width, titleShape.Height));
        }

        protected virtual void OnTitleChanged()
        {
            Invalidate(InvalidationFlag.Layout);
        }

        protected virtual void OnTitleShapeChanged(Shape oldValue)
        {
            if (oldValue != null)
            {
                Shapes.Remove(oldValue);
                oldValue.Dispose();
            }
            if (titleShape != null)
            {
                Shapes.AddFirst(titleShape);
            }
            Invalidate(InvalidationFlag.Layout);
        }

        protected override void ApplyStyle()
        {
            base.ApplyStyle();
            if (toolbarBackground == null) ToolbarBackground = CreateToolbarBackground();
        }

        /// <summary>
        /// Notifies the window that the client bounds need to be updated.
        /// This happens for instance, when a toolbar is expanding or collapsing.
        /// </summary>
        public virtual void UpdateClientBounds()
        {
            Invalidate(InvalidationFlag.Layout);
            Control focused = Screen.FocusedControl;
            if (focused is IInputControl) focused.BringIntoView(false);
        }

        protected virtual Shape CreateToolbarBackground()
        {
            return PhoneColors.Black;
        }

        protected override void PreLayout()
        {
            //            base.PreLayout();

            if (CheckFlag(InvalidationFlag.Size | InvalidationFlag.Margin | InvalidationFlag.Layout))
            {
                if (toolbarBackground != null) toolbarBackground.Opacity = toolbarOpacity;
                if (keyboardContainer != null)
                {
                    KeyboardContainer.Bounds = KeyboardRect;
                }
                controlsPanel.Bounds = ClientBounds;
                toolbarContainer.Bounds = ToolbarRect;
                if (visibleToolbar != null)
                {
                    SetToolbarSize(visibleToolbar);
                    visibleToolbar.Opacity = (int)(toolbarTransition * Control.Opaque);
                }
                if (titleShape != null)
                {
                    Rectangle rect = GetTitleRect();
                    titleShape.Bounds = titleMargin.Layout(titleShape.Bounds, rect.Size);
                }
            }
        }

        private void SetToolbarSize(ToolbarBase toolbar)
        {
            Orientation o = ToolbarOrientation;
            toolbar.Orientation = o;
            if (o == Orientation.Portrait)
            {
                toolbar.Width = Width;
            }
            else
            {
                toolbar.Height = Height;
            }
        }

        protected virtual void OnToolbarOpacityChanged()
        {
            if (visibleToolbar != null) Invalidate(InvalidationFlag.Layout);
        }

        protected virtual void OnKeyboardVisibilityChanged()
        {
            bool visible = keyboardVisibility != 0f;
            KeyboardContainer.Visible = visible;
            Keyboard.Visible = visible;
            if (keyboardVisibility == 0f) OnKeyboardHidden();
            else if (keyboardVisibility == 1f) OnKeyboardShown();
            RaiseViewChanged(this);
            Invalidate(InvalidationFlag.Layout);
        }

        private void OnKeyboardShown()
        {
            RaiseEvent(KeyboardShownEvent);
        }

        private void OnKeyboardHidden()
        {
            RaiseEvent(KeyboardHiddenEvent);
        }

        protected virtual void OnToolbarVisibilityChanged()
        {
            Invalidate(InvalidationFlag.Layout);
        }

        protected override Shape CreateDefaultBackground()
        {
            return Color.Black;
        }

        protected override void OnSizeChanged()
        {
            IsKeyboardVisible = false;
            base.OnSizeChanged();
        }

        protected virtual void OnKeyboardVisibleChanged(bool value)
        {
            if (value)
            {
                if (visibleToolbar != null)
                {
                    visibleToolbar.IsExpanded = false;
                }
                KeyboardContainer.Visible = true;
                SetState("KeyboardShown");
            }
            else
            {
                Invalidate(InvalidationFlag.Layout);
                SetState("KeyboardHidden");
            }
            if (ShowKeyboardChanged != null) ShowKeyboardChanged(this, EventArgs.Empty);
            UpdateClientBounds();
        }

        /// <summary>
        /// Occurs when the visibility of the toolbar changes.
        /// </summary>
        protected virtual void OnShowToolbarChanged()
        {
            if (!IsToolbarVisible) IsKeyboardVisible = false;
            if (ShowToolbarChanged != null) ShowToolbarChanged(this, EventArgs.Empty);
            Invalidate(InvalidationFlag.LayoutAppearance);
        }

        private void OnKeyboardAlwaysVisibleChanged()
        {
            if (isKeyboardAlwaysVisible) IsKeyboardVisible = true;
        }

        protected override void OnShowing()
        {
            if (toolbar != null) toolbar.HideButtons(false);
            base.OnShowing();
        }

        protected override void OnHiding()
        {
            if (toolbar != null) toolbar.HideButtons(true);
            IsKeyboardVisible = false;
            base.OnHiding();
        }

        protected override void OnShown()
        {
            base.OnShown();
            if (toolbar != null) toolbar.ShowButtons(true);
        }

        private static float ValidateKeyboardVisibility(float value)
        {
            if (value < 0f) return 0;
            else if (value > 1f) return 1f;
            return value;
        }

        private static float ValidateToolbarVisibility(float value)
        {
            if (value < -1f) value = -1f; else if (value > 1f) value = 1f;
            return value;
        }

        protected override void OnVisibleChanged()
        {
            if (!Visible) isKeyboardVisible = false;
            base.OnVisibleChanged();
        }

        /// <summary>
        /// Occurs when the "Home" Hardware key is pressed (which is the left button) or GoHome executed.
        /// </summary>
        protected virtual void OnHome(HandledEventArgs e)
        {
            RaiseEvent<HandledEventArgs>(HomeEvent, e);
        }

        /// <summary>
        /// Occurs when the "Back" Hardware key is pressed (which is the left button) or GoBack() executed.
        /// </summary>
        protected virtual void OnBack(HandledEventArgs e)
        {
            RaiseEvent<HandledEventArgs>(BackEvent, e);
        }

        protected override void OnOrientationChanged(object sender, EventArgs e)
        {
            if (visibleToolbar != null) visibleToolbar.IsExpanded = false;
            bool isKeyboardVisible = IsKeyboardVisible;
            KeyboardVisibility = 0f;
            this.isKeyboardVisible = false;
            IsKeyboardVisible = isKeyboardVisible;
            base.OnOrientationChanged(sender, e);
            Invalidate(InvalidationFlag.LayoutAppearance);
        }

        public void CollapseToolbar(Control sender)
        {
            if (visibleToolbar != null && visibleToolbar != sender)
            {
                if (!visibleToolbar.IsAncestorOf(sender))
                {
                    visibleToolbar.IsExpanded = false;
                }
            }
        }

        internal void ToggleSymbols()
        {
            showSymbols ^= true;
            if (showSymbols) Keyboard.State = KeyboardState.Control;
            IsKeyboardVisible = showSymbols;
        }

        protected virtual void OnToolbarChanged(ToolbarBase oldValue)
        {
            if (toolbar != null)
            {
                toolbar.Window = this;
                toolbar.IsExpanded = false;

                // the toolbar won't animate if not initialized, therefore preload it in that case:
                if (this.IsInitialized && !toolbar.IsInitialized) toolbar.PreLoad();
            }
            if (oldValue != null)
            {
                oldValue.IsExpanded = false;
                oldValue.RemoveFromParent();
            }
            if (oldValue != null && !oldValue.AreButtonsHidden)
            {
                visibleToolbar = oldValue;
                oldValue.ButtonsHidden += new EventHandler(OnToolbarButtonsHidden);
                if (toolbar != null) toolbar.HideButtons(false);
                oldValue.HideButtons(true);
            }
            else
            {
                visibleToolbar = toolbar;
                if (toolbar != null)
                {
                    toolbar.HideButtons(false);
                    toolbar.ShowButtons(true);
                }
            }
            ToolbarTransition = toolbar != null ? 1f : 0f;
            toolbarContainer.Control = visibleToolbar;
            Invalidate(InvalidationFlag.Layout);

        }

        private void OnToolbarButtonsHidden(object sender, EventArgs e)
        {
            ToolbarBase oldToolbar = sender as ToolbarBase;
            oldToolbar.Window = null;
            oldToolbar.ButtonsHidden -= OnToolbarButtonsHidden;
            toolbarContainer.Control = toolbar;
            visibleToolbar = toolbar;
            if (toolbar != null) toolbar.ShowButtons(true);
            Invalidate(InvalidationFlag.Layout);
        }

        /// <summary>
        /// Occurs when the exit application "OK" button of the phone is pressed.
        /// By default, this causes a dialog to appear to select wether to éxit the application.
        /// </summary>
        public virtual void OnExitApplication()
        {
            ExitAppUtil.Exit();
        }

        #endregion
        #region events

        protected static readonly SparseEvent KeyboardHiddenEvent = new SparseEvent();
        protected static readonly SparseEvent KeyboardShownEvent = new SparseEvent();
        protected static readonly SparseEvent HomeEvent = new SparseEvent();
        protected static readonly SparseEvent BackEvent = new SparseEvent();

        /// <summary>
        /// Occurs when the visibility of the toolbar changes.
        /// </summary>
        public event EventHandler ShowToolbarChanged;
        public event EventHandler ShowKeyboardChanged;

        public event EventHandler KeyboardHidden
        {
            add { AddHandler(KeyboardHiddenEvent, value); }
            remove { RemoveHandler(KeyboardHiddenEvent, value); }
        }

        public event EventHandler KeyboardShown
        {
            add { AddHandler(KeyboardShownEvent, value); }
            remove { RemoveHandler(KeyboardShownEvent, value); }
        }


        /// <summary>
        /// Occurs when the home button is pressed.
        /// </summary>
        public event EventHandler Home
        {
            add { AddHandler(HomeEvent, value); }
            remove { RemoveHandler(HomeEvent, value); }
        }

        /// <summary>
        /// Occurs when the back button is pressed.
        /// </summary>
        public event EventHandler Back
        {
            add { AddHandler(BackEvent, value); }
            remove { RemoveHandler(BackEvent, value); }
        }

        /// <summary>
        /// Navigates back to the previous page.
        /// </summary>
        public void GoBack()
        {
            OnBack(new HandledEventArgs());
        }

        /// <summary>
        /// Navigates to the home page.
        /// </summary>
        public void GoHome()
        {

            OnHome(new HandledEventArgs());
        }



        #endregion
        #region threading

        private FormThreads threads;

        protected FormThreads Threads
        {
            get
            {
                lock (this)
                {
                    if (threads == null) threads = new FormThreads();
                    return threads;
                }
            }
        }

        /// <summary>
        /// Exits all running form threads.
        /// </summary>
        public void ExitAllThreads()
        {
            if (threads != null) threads.ExitAll();
        }

        /// <summary>
        /// Enqueues a new method to run in a separate thread as long as the form is alive.
        /// The thread that hosts the method is aborted as soon as the page is hiding, hidden or disposing.
        /// Access to properties of controls inside the specified method must be invoked with Control.Invoke() method.
        /// </summary>
        /// <param name="t">ThreadStart method to execute in a separate thread.</param>
        public void EnqueueThread(ThreadStart t)
        {
            if (t == null) throw new ArgumentNullException("t");
            Threads.Enqueue(t);
        }

        /// <summary>
        /// Enqueues a new method to run in a separate thread as long as the form is alive.
        /// The thread that hosts the method is aborted as soon as the page is hiding, hidden or disposing.
        /// Access to properties of controls inside the specified method must be invoked with Control.Invoke() method.
        /// </summary>
        /// <param name="callback">Callback method to execute in a spearate thread</param>
        /// <param name="obj">Parameter to pass the method.</param>
        public void EnqueueThread(WaitCallback callback, object obj)
        {
            if (callback == null) throw new ArgumentNullException("callBack");
            Threads.Enqueue(callback, obj);
        }

        #endregion
    }
}
